package com.echo.boot.design.turing.prototype;

import lombok.SneakyThrows;

import java.io.*;

/**
 * Created with IntelliJ IDEA
 * Created By CQ
 * Date: 2020/8/9
 * Time: 20:14
 *
 * @author Administrator
 * 原型模式
 * 指原型实例指定创建对象的种类,并且通过拷贝这些原型创建新得对象·
 * Cloneable 接口
 * 浅拷贝,深拷贝
 * 序列化实现
 */
public class Prototype {
    public static void main(String[] args) throws CloneNotSupportedException {
        Product product = new Product("part1", "part2", "part3", "part4", "part5", new Item("item"));
        Product clone = product.clone();
        System.out.println(product);
        System.out.println(clone);


    }
}

class Item implements Cloneable, Serializable {
    private static final long serialVersionUID = -6736565693989887751L;
    private String itemPart;

    public Item(String itemPart) {
        this.itemPart = itemPart;
    }

    @Override
    protected Item clone() throws CloneNotSupportedException {
        return (Item) super.clone();
    }

    @Override
    public String toString() {
        return "hashCode " + this.hashCode() + " Item{" +
                "itemPart='" + itemPart + '\'' +
                '}';
    }
}

// 复杂对象,但变化的属性很少,可以通实现 Cloneable 接口 来完成复制对象。
class Product implements Cloneable, Serializable {

    private static final long serialVersionUID = 6686025068556239L;
    private String part1;
    private String part2;
    private String part3;
    private String part4;
    private String part5;

    // .............
    // 如果 Item 对象不实现 Cloneable 接口,那么拷贝的对象是同一个对象,如果原数据 被修改,拷贝出的对象一会被修改,这是浅拷贝
    // Item 实现 Cloneable 接口,来实现 深拷贝 ,拷贝出来对象不是一个对象,原数据 被修改,拷贝的对象不会修改.
    // 也可以实现  Serializable 接口来 深度拷贝。
    private Item item;


    public Product() {
    }

    public Product(String part1, String part2, String part3, String part4, String part5, Item item) {
        this.part1 = part1;
        this.part2 = part2;
        this.part3 = part3;
        this.part4 = part4;
        this.part5 = part5;
        this.item = item;
    }

    @Override
    public String toString() {
        return "hashCode " + this.hashCode() + " Product{" +
                "part1='" + part1 + '\'' +
                ", part2='" + part2 + '\'' +
                ", part3='" + part3 + '\'' +
                ", part4='" + part4 + '\'' +
                ", part5='" + part5 + '\'' +
                ", item=" + item +
                '}';
    }

    @SneakyThrows
    @Override
    protected Product clone() throws CloneNotSupportedException {
//        Product clone = (Product) super.clone();
//        // 可变对象实现cloneable 接口来实现,深拷贝
//        Item item = clone.item.clone();
//        clone.setItem(item);
//        return clone;


        // 序列化来实现 深拷贝
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        try (ObjectOutputStream oos = new ObjectOutputStream(outputStream)) {
            oos.writeObject(this);
        } catch (Exception e) {
            e.printStackTrace();
        }


        ByteArrayInputStream inputStream = new ByteArrayInputStream(outputStream.toByteArray());
        try (ObjectInputStream ois = new ObjectInputStream(inputStream)) {
            Product product = ((Product) (ois.readObject()));
            return product;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public String getPart1() {
        return part1;
    }

    public void setPart1(String part1) {
        this.part1 = part1;
    }

    public String getPart2() {
        return part2;
    }

    public void setPart2(String part2) {
        this.part2 = part2;
    }

    public String getPart3() {
        return part3;
    }

    public void setPart3(String part3) {
        this.part3 = part3;
    }

    public String getPart4() {
        return part4;
    }

    public void setPart4(String part4) {
        this.part4 = part4;
    }

    public String getPart5() {
        return part5;
    }

    public void setPart5(String part5) {
        this.part5 = part5;
    }

    public Item getItem() {
        return item;
    }

    public void setItem(Item item) {
        this.item = item;
    }
}
